#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "aboutdialog.h"
#include "mainshare.h"
#include "reportdialog.h"
#include "srsettingsdialog.h"
#include "mailsettingsdialog.h"
#include "resultdialog.h"
#include "../ImageView/viewshare.h"
#include "../ImageView/dicomimageview.h"
#include "../ImageView/thumbnailbarwidget.h"
#include "../ImageView/imageloadthread.h"
#include "../ImageView/dicomimagelabel.h"
#include "../ImageView/imageinstance.h"
#include "../algorithms/AlgorithmShare.h"
#include "../algorithms/radiomicsalgorithm.h"

#include <QPdfWriter>
#include <QFileDialog>
#include <QMessageBox>
#include <QGridLayout>
#include <QSettings>
#include <QKeyEvent>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QTimer>
#include <QTextStream>

#define RADIOMICS_LOG_FILE "radiomics.log.txt"

MainWindow::MainWindow(QWidget *parent) :
    currentView(0),
    viewMaximised(0),
    mouseSeed(0),
    svmScore(0),
    eTimer(new QElapsedTimer),
    algo(new RadiomicsAlgorithm(this)),
    stage(PS_NoSeed),
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    init();
}

MainWindow::~MainWindow()
{
    QSettings s;
    AlgoCombo combo = algo->getAlgorithmCombo();
    s.setValue(SEGMENT_ALGO_INUSE, int(combo.segment));
    s.setValue(EXTRACT_ALGO_INUSE, int(combo.extract));
    s.setValue(PREDICT_ALGO_INUSE, int(combo.predict));
    s.setValue(MPR_VIEW, ui->actionMPR->isChecked());
    s.setValue(TUMOR_VIEW, ui->actionTumor->isChecked());
    s.setValue(TUMOR_AREA, ui->seedAreaSpin->value());

    delete eTimer;
    delete ui;
}

void MainWindow::init()
{
    viewLayout = new QGridLayout;
    viewLayout->setContentsMargins(0, 0, 0, 0);
    viewLayout->setSpacing(0);
    xyView = new DicomImageView(VT_XYPlane);
    xzView = new DicomImageView(VT_XZPlane);
    yzView = new DicomImageView(VT_YZPlane);
    viewLayout->addWidget(xzView, 0, 0);
    viewLayout->addWidget(yzView, 1, 0);
    viewLayout->addWidget(xyView, 0, 1, 2, 1);

    connect(xyView, SIGNAL(windowChanged()), xzView, SLOT(updateImage()));
    connect(xyView, SIGNAL(windowChanged()), yzView, SLOT(updateImage()));
    connect(yzView, SIGNAL(windowChanged()), xyView, SLOT(updateImage()));
    connect(yzView, SIGNAL(windowChanged()), xzView, SLOT(updateImage()));
    connect(xzView, SIGNAL(windowChanged()), xyView, SLOT(updateImage()));
    connect(xzView, SIGNAL(windowChanged()), yzView, SLOT(updateImage()));
    connect(xyView, SIGNAL(viewClicked(DicomImageView*)),
            this, SLOT(onViewClicked(DicomImageView*)));
    connect(xyView, SIGNAL(viewDoubleclicked(DicomImageView*)),
            this, SLOT(onViewDoubleClicked(DicomImageView*)));
    connect(xyView, SIGNAL(thumbnailDraggedIn(DicomImageLabel*)),
            this, SLOT(onImageDoubleClicked(DicomImageLabel*)));
    connect(xyView, SIGNAL(seedChoosing(int,int,int,int,DicomImageView*)),
            this, SLOT(onSeedChoosing(int,int,int,int,DicomImageView*)));
    connect(xyView, SIGNAL(seedFinished(bool)), this, SLOT(onSeedFinished(bool)));

    connect(xzView, SIGNAL(viewClicked(DicomImageView*)),
            this, SLOT(onViewClicked(DicomImageView*)));
    connect(xzView, SIGNAL(viewDoubleclicked(DicomImageView*)),
            this, SLOT(onViewDoubleClicked(DicomImageView*)));
    connect(xzView, SIGNAL(thumbnailDraggedIn(DicomImageLabel*)),
            this, SLOT(onImageDoubleClicked(DicomImageLabel*)));
    connect(xzView, SIGNAL(seedChoosing(int,int,int,int,DicomImageView*)),
            this, SLOT(onSeedChoosing(int,int,int,int,DicomImageView*)));
    connect(xzView, SIGNAL(seedFinished(bool)), this, SLOT(onSeedFinished(bool)));

    connect(yzView, SIGNAL(viewClicked(DicomImageView*)),
            this, SLOT(onViewClicked(DicomImageView*)));
    connect(yzView, SIGNAL(viewDoubleclicked(DicomImageView*)),
            this, SLOT(onViewDoubleClicked(DicomImageView*)));
    connect(yzView, SIGNAL(thumbnailDraggedIn(DicomImageLabel*)),
            this, SLOT(onImageDoubleClicked(DicomImageLabel*)));
    connect(yzView, SIGNAL(seedChoosing(int,int,int,int,DicomImageView*)),
            this, SLOT(onSeedChoosing(int,int,int,int,DicomImageView*)));
    connect(yzView, SIGNAL(seedFinished(bool)), this, SLOT(onSeedFinished(bool)));

    ui->viewContainer->setLayout(viewLayout);
    thumbnailBar = new ThumbnailBarWidget;
    ui->thumbnailScrollArea->setWidget(thumbnailBar);

    connect(thumbnailBar, SIGNAL(seriesInserted(SeriesInstance*)),
            this, SLOT(onSeriesInserted(SeriesInstance*)));
    connect(thumbnailBar, SIGNAL(imageDoubleClicked(DicomImageLabel*)),
            this, SLOT(onImageDoubleClicked(DicomImageLabel*)));
    connect(thumbnailBar, SIGNAL(currentChanged(DicomImageLabel*)),
            this, SLOT(onImageChanged(DicomImageLabel*)));

    connect(algo, SIGNAL(segmentFinished(bool,QString)), this, SLOT(onSegmentFinished(bool,QString)));
    connect(algo, SIGNAL(extractFinished(bool,QString)), this, SLOT(onExtractFinished(bool,QString)));
    connect(algo, SIGNAL(predictFinished(bool,QString)), this, SLOT(onPredictFinished(bool,QString)));

    // Implement algorithm options
    segmGrp = new QActionGroup(this);
    extrGrp = new QActionGroup(this);
    predGrp = new QActionGroup(this);

    const AlgoStringTables &tables = algo->getAlgoStringTables();
    QAction *action;
    for (int i = 0; i < AS_Count; ++i) {
        action = ui->menuSegment->addAction(tables.SegmAlgoNames.at(i));
        action->setCheckable(true);
        segmGrp->addAction(action);
    }
    for (int i = 0; i < AE_Count; ++i) {
        action = ui->menuExtract->addAction(tables.extrAlgoNames.at(i));
        action->setCheckable(true);
        extrGrp->addAction(action);
    }
    for (int i = 0; i < AP_Count; ++i) {
        action = ui->menuPredict->addAction(tables.predAlgoNames.at(i));
        action->setCheckable(true);
        predGrp->addAction(action);
    }

    connect(segmGrp, SIGNAL(triggered(QAction*)), this, SLOT(updateAlgoOptions()));
    connect(extrGrp, SIGNAL(triggered(QAction*)), this, SLOT(updateAlgoOptions()));
    connect(predGrp, SIGNAL(triggered(QAction*)), this, SLOT(updateAlgoOptions()));

    QSettings s;
    ui->actionMPR->setChecked(s.value(MPR_VIEW, true).toBool());
    ui->actionTumor->setChecked(s.value(TUMOR_VIEW, true).toBool());
    on_actionTumor_triggered(ui->actionTumor->isChecked());
    ui->seedAreaSpin->setValue(s.value(TUMOR_AREA, 500).toInt());
    int idx = s.value(SEGMENT_ALGO_INUSE, 0).toInt();
    if (idx>=0&&idx<segmGrp->actions().size()) segmGrp->actions().at(idx)->setChecked(true);
    idx = s.value(EXTRACT_ALGO_INUSE, 0).toInt();
    if (idx>=0&&idx<extrGrp->actions().size()) extrGrp->actions().at(idx)->setChecked(true);
    idx = s.value(PREDICT_ALGO_INUSE, 0).toInt();
    if (idx>=0&&idx<predGrp->actions().size()) predGrp->actions().at(idx)->setChecked(true);
    updateAlgoOptions();
    updateUiButtons();
    ui->statusLabel->setText(tr("Please load images"));

    connect(ui->chooseButton, SIGNAL(clicked(bool)), this, SLOT(on_actionChoose_Seed_triggered(bool)));
    connect(ui->runButton, SIGNAL(clicked()), this, SLOT(on_actionRun_All_triggered()));
    connect(ui->resultButton, SIGNAL(clicked()), this, SLOT(on_actionResult_triggered()));
    connect(ui->seedXSpin, SIGNAL(valueChanged(int)), this, SLOT(onSeedUiChanged()));
    connect(ui->seedYSpin, SIGNAL(valueChanged(int)), this, SLOT(onSeedUiChanged()));
    connect(ui->seedZSpin, SIGNAL(valueChanged(int)), this, SLOT(onSeedUiChanged()));
}

void MainWindow::disableUi(bool yes)
{
    ui->seedXSpin->setReadOnly(yes);
    ui->seedYSpin->setReadOnly(yes);
    ui->seedZSpin->setReadOnly(yes);
    ui->actionChoose_Seed->setDisabled(yes);
    ui->chooseButton->setDisabled(yes);
    ui->actionSegment->setDisabled(yes);
    ui->actionExtract->setDisabled(yes);
    ui->actionPredict->setDisabled(yes);
    ui->actionRun_All->setDisabled(yes);
    ui->runButton->setDisabled(yes);
    ui->actionResult->setDisabled(yes);
    ui->resultButton->setDisabled(yes);
}

void MainWindow::updateUiButtons()
{
    disableUi(true);
    if (!xyView->getSeriesInstance()) return;

    if (stage == PS_NoSeed || stage == PS_SeedChoosing ||
            stage == PS_SeedOk || stage == PS_SegmentFailed ||
            stage == PS_Segmenting) {
        xyView->setMaskVolume(0, 0, 0);
        xzView->setMaskVolume(0, 0, 0);
        yzView->setMaskVolume(0, 0, 0);
    }
    ui->actionStop->setEnabled((stage == PS_Segmenting ||
                                stage == PS_Extracting ||
                                stage == PS_Predicting));

    switch (stage) {
    case PS_PredictOk:
        ui->actionResult->setEnabled(true);
        ui->resultButton->setEnabled(true);
        ui->actionReport->setEnabled(true);
    case PS_PredictFailed:
    case PS_ExtractOk:
        ui->actionPredict->setEnabled(true);
    case PS_ExtractFailed:
    case PS_SegmentOk:
        ui->actionExtract->setEnabled(true);
    case PS_SeedOk:
    case PS_SegmentFailed:
        ui->actionRun_All->setEnabled(true);
        ui->runButton->setEnabled(true);
        ui->actionSegment->setEnabled(true);
    case PS_NoSeed:
        ui->actionChoose_Seed->setEnabled(true);
        ui->chooseButton->setEnabled(true);
        break;
    case PS_SeedChoosing:
        ui->actionChoose_Seed->setEnabled(true);
        ui->chooseButton->setEnabled(true);
        ui->seedXSpin->setReadOnly(false);
        ui->seedYSpin->setReadOnly(false);
        ui->seedZSpin->setReadOnly(false);
        break;
    }
}

void MainWindow::on_actionLoad_Images_triggered()
{
    QSettings s;
    QString dirStr = s.value(OPEN_FILEPATH, ".").toString();
    dirStr = QFileDialog::getExistingDirectory(this, tr("Load Images"), dirStr);
    if (!dirStr.isEmpty()) {
        s.setValue(OPEN_FILEPATH, dirStr);
        xyView->setSeriesInstance(0);
        yzView->setSeriesInstance(0);
        xzView->setSeriesInstance(0);
        stage = PS_NoSeed;
        algo->terminate();
        updateUiButtons();
        thumbnailBar->clear();
        loadImagesFromDir(dirStr);
    }
}

void MainWindow::on_actionAppend_Images_triggered()
{
    QSettings s;
    QString dirStr = s.value(OPEN_FILEPATH, ".").toString();
    dirStr = QFileDialog::getExistingDirectory(this, tr("Load Images"), dirStr);
    if (!dirStr.isEmpty()) {
        s.setValue(OPEN_FILEPATH, dirStr);
        loadImagesFromDir(dirStr);
    }
}

void MainWindow::loadImagesFromDir(const QString &dirStr)
{
    QDir dir(dirStr);
    QStringList files = dir.entryList(QDir::Files);
    for (int i = 0; i < files.size(); ++i)
        files[i] = dirStr + "/" + files.at(i);
    thumbnailBar->appendImageFiles(files);
    QStringList dirs = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot);
    foreach (const QString &d, dirs) {
        loadImagesFromDir(dirStr + "/" + d);
    }
}

void MainWindow::on_actionLoad_Prognostic_triggered()
{
    QSettings s;
    QString prog = s.value(PROGNOSTIC_FILEPATH, ".").toString();
    prog = QFileDialog::getOpenFileName(this, tr("Load Prognostic File"), prog, tr("Prognostic File (*.data)"));
    if (!prog.isEmpty()) {
        s.setValue(PROGNOSTIC_FILEPATH, prog);
        bool sameFile = true;
        if (QFileInfo(PROGNOSTIC_FEATURE_FILE).absoluteFilePath() != prog) {
            QFile::remove(PROGNOSTIC_FEATURE_FILE);
            sameFile = false;
        }
        if (sameFile || QFile::copy(prog, PROGNOSTIC_FEATURE_FILE)) {
            stage = PS_ExtractOk;
            ui->actionPredict->setEnabled(true);
            ui->statusLabel->setText(tr("Prognostic file loaded"));
        } else {
            ui->actionPredict->setEnabled(false);
            ui->statusLabel->setText(tr("Please load images"));
            QMessageBox::critical(this, tr("Load Prognostic File"), tr("Load prognositc file failed."));
        }
    }
}

void MainWindow::on_actionSave_Prognostic_triggered()
{
    QSettings s;
    QString prog = s.value(PROGNOSTIC_FILEPATH, ".").toString();
    prog = QFileDialog::getSaveFileName(this, tr("Save Prognostic File"), prog, tr("Prognostic File (*.data)"));
    if (!prog.isEmpty()) {
        s.setValue(PROGNOSTIC_FILEPATH, prog);
        if (QFile(prog).exists() &&
                (QMessageBox::Ok == QMessageBox::question(this, tr("Save Prognostic File"),
                                                          tr("%1 already exists, overwrite it?").arg(prog),
                                                          QMessageBox::Ok|QMessageBox::Cancel))) {
            if (!QFile::remove(prog))
                QMessageBox::critical(this, tr("Remove File"), tr("%1 remove failed.").arg(prog));
        }
        QFile::copy(PROGNOSTIC_FEATURE_FILE, prog);
    }
}

void MainWindow::on_actionQuit_triggered()
{
    close();
}

void MainWindow::on_actionChoose_Seed_triggered(bool checked)
{
    if (checked) {
        xyView->chooseSeed();
        xzView->chooseSeed();
        yzView->chooseSeed();
    } else {
        xyView->onSeedFinished(false);
        xzView->onSeedFinished(false);
        yzView->onSeedFinished(false);
    }
    stage = PS_SeedChoosing;
    ui->statusLabel->setText(checked?tr("Seed Choosing..."):tr("Please choose seed"));
    ui->actionChoose_Seed->setChecked(checked);
    ui->chooseButton->setChecked(checked);
    updateUiButtons();
}

void MainWindow::on_actionSegment_triggered()
{
    runAll = false;
    doSegment();
}

void MainWindow::doSegment()
{
    stage = PS_Segmenting;
    ui->statusLabel->setText(tr("Segmenting..."));
    updateUiButtons();

    const ushort **vol;
    ulong w, h, s;
    xyView->getRawVolume(vol, w, h, s);
    algo->setSeriesVolume(vol, w, h, s);
    algo->setSeedInfo(ui->seedXSpin->value(), ui->seedYSpin->value(), ui->seedZSpin->value(),
                      ui->seedValSpin->value(), ui->seedAreaSpin->value());
    algo->doSegment();
    eTimer->start();
}

void MainWindow::on_actionExtract_triggered()
{
    runAll = false;
    doExtract();
}

void MainWindow::doExtract()
{
    stage = PS_Extracting;
    ui->statusLabel->setText(tr("Extracting..."));
    updateUiButtons();
    if (!runAll) eTimer->start();
    algo->doExtract();
}

void MainWindow::on_actionPredict_triggered()
{
    runAll = false;
    doPredict();
}

void MainWindow::doPredict()
{
    stage = PS_Predicting;
    ui->statusLabel->setText(tr("Predicting..."));
    updateUiButtons();
    if (!runAll) eTimer->start();
    algo->doPredict();
}

void MainWindow::on_actionRun_All_triggered()
{
    runAll = true;
    doSegment();
}

void MainWindow::on_actionStop_triggered()
{
    ui->statusLabel->setText(tr("Terminated"));
    algo->terminate();
    switch (stage) {
    case PS_Segmenting:
        stage = PS_SegmentFailed;
        break;
    case PS_Extracting:
        stage = PS_ExtractFailed;
        break;
    case PS_Predicting:
        stage = PS_PredictFailed;
        break;
    }
    updateUiButtons();
}

void MainWindow::on_actionResult_triggered()
{
    ResultDialog dialog(this);
    dialog.setSVMScore(svmScore);
    dialog.exec();
}

void MainWindow::on_actionReport_triggered()
{
    StudyRecord rec;
    xyView->getStudyRecord(rec);
    ReportDialog dialog(rec, this);
    QImage axial = xyView->getRenderedTumorImage();
    QImage coronal = xzView->getRenderedTumorImage();
    QImage sagittal = yzView->getRenderedTumorImage();
    dialog.setReportImages(axial, coronal, sagittal);
    dialog.setSVMScore(svmScore);
    dialog.exec();
}

void MainWindow::on_actionLog_File_triggered()
{
    QDesktopServices::openUrl(QUrl::fromLocalFile(RADIOMICS_LOG_FILE));
}

void MainWindow::on_actionReport_Format_triggered()
{
    SRSettingsDialog dialog(this);
    dialog.exec();
}

void MainWindow::on_actionAuto_Email_triggered()
{
    MailSettingsDialog dialog(this);
    dialog.exec();
}

void MainWindow::on_actionMPR_toggled(bool checked)
{
    xzView->setVisible(checked);
    yzView->setVisible(checked);
    if (checked) {
        xzView->setSeriesInstance(xyView->getSeriesInstance());
        yzView->setSeriesInstance(xyView->getSeriesInstance());
    } else {
        xzView->clear();
        yzView->clear();
    }
}

void MainWindow::on_actionTumor_triggered(bool checked)
{
    xyView->showTumor(checked);
    xzView->showTumor(checked);
    yzView->showTumor(checked);
}

void MainWindow::on_actionManual_PDF_triggered()
{
    QDesktopServices::openUrl(QUrl::fromLocalFile("Radiomics User Manual.pdf"));
}

void MainWindow::on_actionAbout_Radiomics_triggered()
{
    AboutDialog dialog(this);
    dialog.exec();
}

void MainWindow::updateAlgoOptions()
{
    int i;
    AlgoCombo combo;

    for (i = 0; i < segmGrp->actions().size(); ++i)
        if (segmGrp->actions().at(i)->isChecked()) break;
    combo.segment = (AlgoSegment)i;
    for (i = 0; i < extrGrp->actions().size(); ++i)
        if (extrGrp->actions().at(i)->isChecked()) break;
    combo.extract = (AlgoExtract)i;
    for (i = 0; i < predGrp->actions().size(); ++i)
        if (predGrp->actions().at(i)->isChecked()) break;
    combo.predict = (AlgoPredict)i;

    algo->setAlgorithmCombo(combo);
}

void MainWindow::onSeedChoosing(int x, int y, int z, int val, DicomImageView *view)
{
    ui->seedXSpin->setValue(x);
    ui->seedYSpin->setValue(y);
    ui->seedZSpin->setValue(z);

    const ushort **vol;
    ulong w, h, s;
    xyView->getRawVolume(vol, w, h, s);
    uint v = vol[z][y*w+x];
    ui->seedValSpin->setValue(v);
    if (view == xyView) {
        xzView->setSeedPos(x, z, y);
        yzView->setSeedPos(y, z, x);
    } else if (view == xzView) {
        xyView->setSeedPos(x, y, z);
        yzView->setSeedPos(y, z, x);
    } else if (view == yzView) {
        xyView->setSeedPos(x, y, z);
        xzView->setSeedPos(x, z, y);
    }
    mouseSeed = true;
}

void MainWindow::onSeedFinished(bool ok)
{
    xyView->setNone();
    xzView->setNone();
    yzView->setNone();
    xyView->onSeedFinished(ok);
    xzView->onSeedFinished(ok);
    yzView->onSeedFinished(ok);
    stage = ok?PS_SeedOk:PS_NoSeed;
    ui->statusLabel->setText(ok?tr("Seed prepared"):tr("Please choose seed"));
    updateUiButtons();
    ui->actionChoose_Seed->setChecked(false);
    ui->chooseButton->setChecked(false);
}

void MainWindow::onSeedUiChanged()
{
    if (mouseSeed) mouseSeed = false;
    else {
        int x = ui->seedXSpin->value();
        int y = ui->seedYSpin->value();
        int z = ui->seedZSpin->value();
        xyView->setSeedPos(x, y, z);
        xzView->setSeedPos(x, z, y);
        yzView->setSeedPos(y, z, x);
        int val;
        if (xyView->getSeedValue(x, y, z, val))
            ui->seedValSpin->setValue(val);
    }
}

void MainWindow::onSeriesInserted(SeriesInstance *series)
{
    if (!xyView->hasSeries()) {
        xyView->setSeriesInstance(series);
        ui->statusLabel->setText(series?tr("Please choose seed"):tr("Please Load Images"));
        int x, y, z;
        if (xyView->getImageDimensions(x, y, z)) {
            ui->seedXSpin->setMaximum(x-1);
            ui->seedYSpin->setMaximum(y-1);
            ui->seedZSpin->setMaximum(z-1);
        }
        if (ui->actionMPR->isChecked()) {
            xzView->setSeriesInstance(series);
            yzView->setSeriesInstance(series);
        }
        updateUiButtons();
    }
}

void MainWindow::onImageDoubleClicked(DicomImageLabel *label)
{
    if (stage == PS_Segmenting || stage == PS_Extracting || stage == PS_Predicting)
        return;
    if (ui->actionChoose_Seed->isChecked()) onSeedFinished(false);

    xyView->setSeriesInstance(label->getSeriesInstance());
    stage = PS_NoSeed;
    updateUiButtons();
    ui->statusLabel->setText(label->getSeriesInstance()?tr("Please choose seed"):tr("Please Load Images"));
    int x, y, z;
    if (xyView->getImageDimensions(x, y, z)) {
        ui->seedXSpin->setMaximum(x-1);
        ui->seedYSpin->setMaximum(y-1);
        ui->seedZSpin->setMaximum(z-1);
    }
    if (ui->actionMPR->isChecked()) {
        xzView->setSeriesInstance(label->getSeriesInstance());
        yzView->setSeriesInstance(label->getSeriesInstance());
    }
}

void MainWindow::onImageChanged(DicomImageLabel *label)
{
    ui->thumbnailScrollArea->ensureWidgetVisible(label);
}

void MainWindow::onViewClicked(DicomImageView *view)
{
    if (currentView) currentView->setHighlight(false);
    currentView = view;
    if (currentView) {
        currentView->setHighlight(true);
        thumbnailBar->setCurrentImageLabel(currentView->getSeriesInstance());
        ui->thumbnailScrollArea->ensureWidgetVisible(thumbnailBar->getCurrentImageLabel());
        emit currentViewChanged(currentView);
    }
}

void MainWindow::onViewDoubleClicked(DicomImageView *view)
{
    if (currentView) currentView->setHighlight(false);
    currentView = view;
    if (currentView) {
        currentView->setHighlight(true);
        thumbnailBar->setCurrentImageLabel(currentView->getSeriesInstance());
        ui->thumbnailScrollArea->ensureWidgetVisible(thumbnailBar->getCurrentImageLabel());
        emit currentViewChanged(currentView);
        if (viewMaximised) {
            xyView->setVisible(true);
            xzView->setVisible(true);
            yzView->setVisible(true);
            viewMaximised = false;
        } else {
            xyView->setVisible(false);
            xzView->setVisible(false);
            yzView->setVisible(false);
            view->setVisible(true);
            viewMaximised = true;
        }
    }
}

void MainWindow::onSegmentFinished(bool ok, const QString &msg)
{
    stage = ok?PS_SegmentOk:PS_SegmentFailed;
    ui->statusLabel->setText(ok?tr("Segmentation Ok"):tr("Segmentation Failed: %1").arg(msg));
    if (ok && runAll) doExtract();
    else {
        updateUiButtons();
        ui->timeDSpin->setValue(eTimer->elapsed()/1000.0);
        eTimer->invalidate();
    }

    if (ok) {
        const uchar **pMask;
        int s, c;
        algo->getTumorMask(pMask, s, c);
        xyView->setMaskVolume(pMask, s, c);
        xzView->setMaskVolume(pMask, s, c);
        yzView->setMaskVolume(pMask, s, c);
    }
}

void MainWindow::onExtractFinished(bool ok, const QString &msg)
{
    stage = ok?PS_ExtractOk:PS_ExtractFailed;
    ui->statusLabel->setText(ok?tr("Extraction Ok"):tr("Extraction Failed: %1").arg(msg));
    if (ok && runAll) doPredict();
    else {
        updateUiButtons();
        ui->timeDSpin->setValue(eTimer->elapsed()/1000.0);
        eTimer->invalidate();
    }
}

void MainWindow::onPredictFinished(bool ok, const QString &msg)
{
    stage = ok?PS_PredictOk:PS_PredictFailed;
    ui->statusLabel->setText(ok?tr("Prediction Ok"):tr("Prediction Failed: %1").arg(msg));
    updateUiButtons();
    ui->timeDSpin->setValue(eTimer->elapsed()/1000.0);
    eTimer->invalidate();

    double nstageScore;
    algo->getPredictResult(svmScore, nstageScore);
    on_actionResult_triggered();

    logInstance();
}

void MainWindow::logInstance()
{
    QFile log(RADIOMICS_LOG_FILE);
    log.open(QIODevice::Append);
    QTextStream out(&log);

    StudyRecord rec;
    xyView->getStudyRecord(rec);
    out << QString("\n********************  %1  ********************\n\n")
           .arg(QDateTime::currentDateTime().toString(SQLITE_DATETIME_FORMAT));
    out << tr("Patient Name: ") + rec.patientName + "\t"
           + tr("Patient Sex: ") + sex2trSex(rec.patientSex) + "\t"
           + tr("Patient Age: ") + rec.patientAge + "\n";
    out << tr("Body Part: ") + rec.bodyPart + "\t"
           + tr("Modality: ") + rec.modality + "\t"
           + tr("Study Date: ") + rec.studyTime.date().toString(SQLITE_DATE_FORMAT) + "\n";
    out << tr("Series No.: ") + rec.seriesNum + "\t"
           + tr("Series Desc: ") + rec.seriesDesc + "\t"
           + tr("Study Desc: ") + rec.studyDesc + "\n\n";
    out << tr("Tumor Seed (X: %1, Y: %2, Z: %3)\tValue: %4\tArea: %5\n")
           .arg(ui->seedXSpin->value())
           .arg(ui->seedYSpin->value())
           .arg(ui->seedZSpin->value())
           .arg(ui->seedValSpin->value())
           .arg(ui->seedAreaSpin->value());
    double svm, nstage;
    algo->getPredictResult(svm, nstage);
    out << tr("Result: ") + ((stage==PS_PredictOk)?tr("Succeeded"):tr("Failed")) + "\t"
           + ui->timeDSpin->text() + "\n";
    out << tr("SVM Score: %1\tNstage Score: %2\n").arg(svm).arg(nstage);
    //out << tr("Tumor Catagory: ") + ui->resultLabel->text() + "\n";
    //out << tr("Health Score: ") + ui->patientScoreLabel->text() + "\n";
    //out << tr("Time Left: ") + ui->lifetimeLabel->text() + "\n";
    //out << tr("N Stage: ") + ui->nstageLabel->text() + "\n";
    //out << tr("Suggested Therapy: ") + ui->suggestLabel->text() + "\n";
    out << QString("\n--------------------  %1  --------------------\n\n").arg(tr("End Seperator"));

    log.close();
}
